/**
 * @file fileio.c
 *
 *  Created on: Mar 29, 2010
 *      Author: Marco Luisi
 */
#include "util.h"
#include "fileio.h"

	///contatore per le matrici caricate con successo.
	int count;

/**
 * @brief Apre e carica in memoria le liste nel file scelto chiamando loadmat fino all'esaurimento del buffer.
 *
 * @param filename
 * @return
 */

int loadFile(char *filename) {
	int fd;
	int rd;
	int dim;
	count = 0;


	char *buffer; /// in buffer viene copiato quanto letto dal file, viene passato come parametro alla prima loadmat
	char *aux = NULL; /// puntatore di appoggio per strtok_r
	char *parse_buffer;
	struct stat statbuf;

	/// apertura e lettura del file.
	EC_M1( fd = open(filename, O_RDONLY) );
	EC_M1( stat(filename, &statbuf) );

	if (!S_ISREG(statbuf.st_mode)) {//ok?
			printf("not reg:\n");
			return -1;
		}
	dim = (int)statbuf.st_size + 1; //+1??
	buffer = malloc(dim * sizeof(char));// ok dim?
	EC_M1(rd = read(fd, buffer,dim));
	printf("Caricato in memoria il file %s , letti = %d bytes\n",filename,rd);

	///parsing del contenuto del buffer.
	parse_buffer = loadMat(buffer,aux);
	printf("temp dopo prima loamad = !%s!\n",parse_buffer);
	while(parse_buffer !=NULL ){ //|| *temp != '\0' //sistemare queste guardie
		parse_buffer = loadMat(NULL, parse_buffer);
		printf("temp dopo loamad = !%s!\n",parse_buffer);
		if(parse_buffer ==NULL){
			printf("NULL\n");
			break;
		}
		if(*parse_buffer == '\0'){
				printf("ZERO\n");
				break;
			}
	}//fine ciclo parsing del file

	printf("DOPO  ciclo LOAD MAT: aux:\n!%s!\n",aux);

	//free(parse_buffer);
	//printf("Free buffer\n");
	free(aux);
	printf("Free aux\n");
	EC_M1_E(close(fd),"errore chiusura file!");
	return 1;
}

//idea strtok tokensu delim fine riga iniziale
//scanf sulla linea
//e poi strtok per ogni linwa da passare a parserow



/**
 * @brief Effettua il parsing del file caricando la matrice in memoria.
 *
 * @param s
 * @param aux
 * @return
 */
char* loadMat(char *s,char* aux) {// portare aux fuori
	extern matrix_l *matlist;
	int i , check;
	char *token;
	char *tmp;
	//char* aux=NULL;

	matrix_t *prova= NULL;
	matrix_l* asd;
	///parametri matrice da passare a newMat
	char *matname;
	int rows;
	int columns;
	double **numbers;

	count = 0;
	//variabile statica che accumula le mat caricate con successo nel caso di ricorsione
	printf("inizio loadmat di !%s!\naux=!%s!\n",s,aux);
	if (s == NULL){ //chiamate successive
		token= strtok_r(NULL,"$",&aux);//taglio tutto quello che c'è prima della prossima matrice
		printf("strtok succ $\n");
		printf("token =!%s!\n",token);
		token = strtok_r(NULL,"#",&aux);
		printf("strtok #\n");
		printf("token =!%s!\n",token);
		printf("aux =!%s!\n",aux);
		if (token == NULL)
			return NULL;
	}
	else{ //prima chiamata
		if(s[0] == '$') {
			s++;
			token = strtok_r(s,"#",&aux);
			printf("strtok #\n");
			printf("token =!%s!\n",token);
			printf("aux =!%s!\n",aux);
		}
		else {
			return s; //non si fa niente si passa ala seconda chiamata i lbuffer intatto
			}
	}
	/**Controlli preliminare della correttezza del parametro
	 * nomemat.
	 *Controllo lunghezza stringa
	 *Controllo correttezza caratteri
	 * rivedere..
	 */
	if (nameCheck(token) == 1){
		//EC_NULL(m->name = strndup(token,NAMELEN)); //portare in EC F
		matname = strndup(token,NAMELEN);//EC
		}
	else{ //non è stato trovato un nome matrice conforme
			//si deve passare all'eventuale prossima matrice sul file
		printf("Nome matrice non conforme..\n");
		goto error;
	}
	printf("loadmat  matname=!%s!\n",matname);

	///parsing #righe
	token = strtok_r(NULL,":",&aux);
	if (token == NULL)
		return NULL;
	printf("strtok :\n");
	printf("token =!%s!\n",token);
	printf("aux =!%s!\n",aux);
	rows = (int)strtol(token, NULL, 10);
	printf("loadmat  rows=!%d!\n",rows);
	if(rows == 0){
		printf("errore righe\n");
		goto error;

	}
	///parsing #colonne
	token = strtok_r(NULL,"/",&aux);
	printf("strtok / \n");
	printf("token =!%s!\n",token);
	printf("aux =!%s!\n",aux);
	columns = (int)strtol(token, NULL, 10);
	printf("loadmat  columns=!%d!\n",columns);
	if(columns == 0){
		printf("errore colonne\n");
		goto error;
	}

	///allocaazione matrice di double
	numbers = calloc(rows, sizeof(double *));
	for (i = 0; i < rows; i++){
		numbers[i] = calloc(columns,sizeof(double)); //EC
	}
	/**parsing linee e riempimento matrice in memoria
	 *  a questo punto:
	 *  - token:contiene i NUMERI da passare al ciclo di parserow!
	 *	 - aux: il resto della matrice e del buffer
	 */
		for(i = 0;i < rows; i++){
			token = strtok_r(NULL,"\n",&aux);
			check = parseRow(token,numbers[i],columns);
			if(check == -1){
				printf(" riga %d!\n",i);
				goto error;
			}
		}

		///tutti i parametri della martice sono stati validati
		///si crea la matrice e la si inserisce nella lista.
		listMat(matlist);
		prova = newMat(matname,rows,columns,numbers);
		printf("prova newmat\n");
		printMat(prova);


		printf("prova inserimento\n");
		if(addMat(&matlist,prova) == 1)
			count++;

		printMat(matlist->matrix);
		printf("stampa 2\n");
		listMat(matlist);



		printf("FINE AUX=!%s!\n",aux);
		printf("FINE S=!%s!\n",s);
		printf("FINE LINE=!%s!\n",token);
		if(*aux == '\0'){ //se non rimane niente ok, funziona
			printf("Fine parsing file\n");

			free(s);
			return NULL; //ok
		}
		tmp = NULL;
//DA CONTROLLARE LE FREE

//IN CASO DI ERRORE SI CHIAMA LA CANCELLAZIONE MATRICE DALLA LISTA!!

	return aux;

	error: //provare ad eliminare i goto
	//delete della matrice
	//strtok_r(NULL,"$",&aux);//taglio tutto quello che c'è prima della prossima matrice
	printf("ERROR AUX=!%s!\n",aux);

	if(*aux =='\0'){ //se prima matrice sputtanat nel nome poi segfault qui alla seconda chiamats
		printf("error 000l\n"); //vedere
		aux = NULL;
	}

	//può anche voler dire non c'è piu quel token particolare nel caso può segnalare che si deve uscire
	return aux;
}



/**
 *
 * @param line
 * @param row
 * @param len
 * @return
 */
int parseRow(char *line,double *row,int len){
	int i;
	int check;
	char *number;
	printf("parserow input = !%s!\n",line);
	for(i = 0; i<len;i++ ){
		if (i == 0){
			number = strtok(line, " ");
		}
		else{
			number = strtok(NULL, " ");//controllo errore formato?
		}
		check = toDouble(number, &row[i]);
		printf("parserow ciclo %d, number = !%s! check =%d\nbuffer=!%s!\n",i,number,check,line);
		switch (check){
				//mettere delle free prima dei return?
				case -1:{ //file non conforme o errore
					printf("Errore nel parsing: elemento %s #%d",number,i);
					return -1;
				}
				case 0:{
					if(i == (len-1) ) {
						printf("Errore nel parsing: elemento %s #%d",number,i);
						return -1;
					}
					break;
					}
				case 1:{
					if (i != len-1){
						printf("Errore nel parsing: elemento %s #%d",number,i);
						return -1;
					}
					break;
					}
				} //fine switch

	}

	printf("FINE PARSEROW\n");

	return 0;

}

/**
 *
 * @param token
 * @return
 */
int nameCheck(char *token){
	int i;
	int len;
	len = strlen(token);
	if(len > NAMELEN)
		return -1;
	if( !(isalpha(token[0])) ){
		return -1; //msg errore
	}
	for (i = 1; i<len; i++) {
		if( !( isalnum(token[i]) ) )
			return -1;
	}
	return 1;
}

/**
 *
 * @param num
 * @param d
 * @return
 */
int toDouble(char *num, double *d) {
	char* c;
	double tmp;
	printf("DEBUG:toDouble di %s\n",num);
	tmp = strtod(num, &c);
	*d = tmp;
	printf("convertito in %f, endpntr =|%s|\n",*d,c);
	if( strcmp(c, ";") == 0 ){
		return 1;
	}

	if(strcmp(c,"\0") != 0){ //se c'è un carattere, o più dopo il numero
		return -1; //errore
	}
	return 0;

}







